#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "Log.hpp"
#include "InetAddr.hpp"
#include "Socket.hpp"

using namespace log_ns;
using namespace socket_ns;

enum {
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR
};

const int glistensockfd = -1;
const int gblcklog = 8;

using service_t = std::function<std::string(std::string&)>;

class TcpServer {
private:
    
    // 创建一个内部类
    struct ThreadData {
        ScokSPtr _tcp_socket;
        InetAdrr _addr;
        TcpServer* _tcp_point;

        
        ThreadData(const ScokSPtr& tcpsocket, const InetAdrr& addr, TcpServer* tcp)
            : _tcp_socket(tcpsocket),
              _addr(addr),
              _tcp_point(tcp)
        {}
    };

    static void* runServer(void* args) {
        // 将线程分离，就不用阻塞的join线程
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        // LOG(INFO, "the sockfd: %d\n", td->_sockfd);

        // 在这里接收消息，然后将消息放入到任务中
        std::string packagestream;
        td->_tcp_socket->Recv(&packagestream);
        
        // 对接收的消息进行处理，然后将处理结束的数据发送回来
        std::string package = td->_tcp_point->_task(packagestream);

        // 现在将package发送出去
        td->_tcp_socket->Send(package);

        td->_tcp_socket->Close();
        // close(); // 将其转化为tcpsocket变量则不需要显示的close了，因为已经析构了
        delete td;
        return nullptr;
    }

public:
    // TcpServer(){}
    TcpServer(service_t task, uint16_t port)
        : _task(task),
          _port(port),
          _isrunning(false),
          _tcp_socket(std::make_shared<TcpSocket>())
    {}

    void Init() {
        _tcp_socket->BuildListenSocket(_port);
    }

    void Start() {
        _isrunning = true;
        while (_isrunning) {
            // std::cout << "start run" << std::endl;
            InetAdrr addr;
            int sockfd = _tcp_socket->CreateAccepte(&addr);
            if (sockfd < 0) {
                LOG(ERROR, "%s get sockfd fail, the reason is %s\n", addr.AddrString().c_str(), strerror(errno));
                continue;
            }
            LOG(INFO, "get sockfd success, sockfd: %d\n", sockfd);

            // 为accept建立一个tcpsocket变量
            ScokSPtr tcp_accept = std::make_shared<TcpSocket>(sockfd);

            // 2. 多线程
            pthread_t tid;
            ThreadData* data = new ThreadData(tcp_accept, addr, this);
            pthread_create(&tid, nullptr, runServer, (void*)data);
        }

        _isrunning = false;
    }

    ~TcpServer() {
        
    }
private:
    uint16_t _port;
    // int _listensocked;
    bool _isrunning;

    service_t _task;

    ScokSPtr _tcp_socket;
};